
#include <anb/common/utils.h>

#include "server_base.h"
#include "utils.h"

namespace anb { namespace net {

server_base::server_base(loop::ptr loop) : uvo_looped(loop, "*server*", uvo::type::uvo_server) {
	m_tcp = get_loop()->create_tcp();
	m_tcp->data = this;
}

server_base::~server_base() {
	stop();
}

int server_base::start(const struct sockaddr_in* addr) {
	int err;

	set_alias(utils::get_addr_name(addr));

	err = uv_tcp_bind(m_tcp, (struct sockaddr*)addr, 0);
	if (err) {
		log_error(err, "bind error");
		return err;
	}

	err = uv_listen((uv_stream_t*)m_tcp, 128, _accepted);
	if (err) {
		log_error(err, "listen error");
		return err;
	}
	log("binded and listened");
	return 0;
}

void server_base::stop() {
	uvo_looped::stop();
	if (m_tcp) {
		loop::close(m_tcp);
		m_tcp = NULL;
	}
}

void server_base::_accepted(uv_stream_t* stream, int err) {
	server_base* s = (server_base*)stream->data;
	s->accepted(err);
}

void server_base::accepted(int err) {
	if (err == -1) {
		log_error(err, "before accept error");
		return;
	}
	uv_tcp_t* tcp = get_loop()->create_tcp();
	err = uv_accept((uv_stream_t*)m_tcp, (uv_stream_t*)tcp);
	if (err != 0) {
		uv_close((uv_handle_t*)tcp, NULL);
		log_error(err, "accept error");
		return;
	}

	connection_base::ptr connection(create_connection(tcp));
	connection->start();
	m_connections[connection->get_peername()] = connection;
}

connection_base* server_base::create_connection(uv_tcp_t* tcp) {
	return new connection_base(get_loop(), tcp);
}

void server_base::connection_stopped(connection_base* connection) {
	const std::string& key = connection->get_peername();
	m_connections.erase(key);
}

} }